package rabbitMqLearn.mq.work_model.client;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import rabbitMqLearn.mq.config.Config;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class MqClient {
    /**
     * 工作队列
     */
    public static void main(String[] args) throws IOException, TimeoutException {
        MqClient mqClient = new MqClient();
        mqClient.topic();
    }

    void sendMag(String s) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Config.HOST);
        factory.setPort(Config.PORT);
        factory.setVirtualHost(Config.VIRTUALHOST);
        factory.setUsername(Config.USERNAME);
        factory.setPassword(Config.PASSWORD);
        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(Config.WORK_QUEUE_NAME, true, false, false, null);

        MqClient mqClient = new MqClient();

        channel.basicPublish("", Config.WORK_QUEUE_NAME, null, s.getBytes());
        System.out.println(" [x] Sent '" + s + "'");
    }

    /**
     * 发布订阅模式
     * 有个exchange的角色 生产者把消息发送给交换机，又交换机的策略来决定这个消息应该发给哪里队列
     * 发布订阅又三种模式
     * Fanout 广播 将消息发送给所有的对队列中
     * Direct 定向 将消息按发送给符合的routing key队列
     * Topic 通配符 将消息发送给符合的 routing pattern队列
     */

    void fanout() throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Config.HOST);
        factory.setPort(Config.PORT);
        factory.setVirtualHost(Config.VIRTUALHOST);
        factory.setUsername(Config.USERNAME);
        factory.setPassword(Config.PASSWORD);
        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();
        /**
         * 声明交换机
         * String exchange, 交换机名称
         * BuiltinExchangeType type, 交换机模式
         * boolean durable, 是否数据持久化
         * boolean autoDelete, 是否自动删除 至少又一个队列和交换机绑定，当这个队列和交换机解绑时删除交换机
         * boolean internal, 是否内部使用 是的话只能通过内部交换机访问到，外部不能直接访问
         * Map<String, Object> arguments) throws IOException; 一些配置参数
         */
        channel.exchangeDeclare(Config.FANOUT_EXCHANGE_NAME, BuiltinExchangeType.FANOUT, true, false, false, null);

        //绑定队列
        channel.queueDeclare(Config.FANOUT_QUEUE_1, true, false, true, null);
        channel.queueDeclare(Config.FANOUT_QUEUE_2, true, false, true, null);

        /**
         * 绑定交换机和队列
         * String queue, 队列名字
         * String exchange,  交换机名字
         * String routingKey, 路由规则
         * Map<String, Object> arguments 参数
         */
        channel.queueBind(Config.FANOUT_QUEUE_1, Config.FANOUT_EXCHANGE_NAME, ""); //为空说明什么都能收到
        channel.queueBind(Config.FANOUT_QUEUE_2, Config.FANOUT_EXCHANGE_NAME, "");

        for(int i = 0; i< 10; i++){
            //发送消息
            String msg = "hello fanout"  + i;
            channel.basicPublish(Config.FANOUT_EXCHANGE_NAME, "", null, msg.getBytes());
            System.out.println(" [x] Sent '" + msg + " "  + i + "'");
        }

        channel.close();
        connection.close();
    }

    /**
     * 路由模式 routing
     * 根据对应的routing key来决定消息流向那个队列
     */
    void routing() throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Config.HOST);
        factory.setPort(Config.PORT);
        factory.setVirtualHost(Config.VIRTUALHOST);
        factory.setUsername(Config.USERNAME);
        factory.setPassword(Config.PASSWORD);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        //声明交换机
        channel.exchangeDeclare(Config.ROUTING_EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true, false, null);

        //声明俩个队列
        channel.queueDeclare(Config.ROUTING_QUEUE_1, true, false, true, null);
        channel.queueDeclare(Config.ROUTING_QUEUE_2, true, false, true, null);

        //绑定俩个队列
        channel.queueBind(Config.ROUTING_QUEUE_1, Config.ROUTING_EXCHANGE_NAME, Config.ROUTING_QUEUE_1_BINDING_KEY);
        channel.queueBind(Config.ROUTING_QUEUE_2, Config.ROUTING_EXCHANGE_NAME, Config.ROUTING_QUEUE_2_BINDING_KEY);

        //发送消息
        for(int i = 0; i< 10; i++){
            String msg = "hello routing" + i;
            String routingKey = i % 2 == 0 ? Config.ROUTING_QUEUE_1_BINDING_KEY : Config.ROUTING_QUEUE_2_BINDING_KEY;
            channel.basicPublish(Config.ROUTING_EXCHANGE_NAME, routingKey, null, msg.getBytes());
            System.out.println(" [x] Sent '" + msg + " routingKey = "  + routingKey + "'");
        }

        channel.close();
        connection.close();
    }

    /**
     * topic 通配符模式
     * 在路由模式上添加了支持通配符来发送消息到队列
     */
    void topic() throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Config.HOST);
        factory.setPort(Config.PORT);
        factory.setVirtualHost(Config.VIRTUALHOST);
        factory.setUsername(Config.USERNAME);
        factory.setPassword(Config.PASSWORD);

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        channel.exchangeDeclare(Config.TOPIC_EXCHANGE_NAME, BuiltinExchangeType.TOPIC, true, false, null);
        channel.queueDeclare(Config.TOPIC_QUEUE_1, true, false, true, null);
        channel.queueDeclare(Config.TOPIC_QUEUE_2, true, false, true, null);

        /**
         * 通配符模式要求routingKey是由 . 分割的字符串 比如 xx.hh
         * 在通配符中由俩种匹配方式
         * * 只允许模糊匹配一个单词 比如 *.hhh.*  ww.hhh.ww ✔️ xx.xx.hhh.xx ×
         * # 可以精准匹配多个单词  比如 #.hhh.#  www.www.ww.hhh.ww.ww ✔️
         *
         */
        channel.queueBind(Config.TOPIC_QUEUE_1, Config.TOPIC_EXCHANGE_NAME, Config.TOPIC_QUEUE_1_BINDING_KEY);
        channel.queueBind(Config.TOPIC_QUEUE_2, Config.TOPIC_EXCHANGE_NAME, Config.TOPIC_QUEUE_2_BINDING_KEY);
//        channel.queueBind(Config.TOPIC_QUEUE_2, Config.TOPIC_EXCHANGE_NAME, "#.#");


        //发送消息
        String msg = "xxx.xxx.hhh";
        channel.basicPublish(Config.TOPIC_EXCHANGE_NAME, msg, null, msg.getBytes());
        System.out.println(" [x] Sent '" + msg + "'");

        msg = "xxx.hhh";
        channel.basicPublish(Config.TOPIC_EXCHANGE_NAME, msg, null, msg.getBytes());
        System.out.println(" [x] Sent '" + msg + "'");

        msg = "aaa.aaa.aaa.www";
        channel.basicPublish(Config.TOPIC_EXCHANGE_NAME, msg, null, msg.getBytes());
        System.out.println(" [x] Sent '" + msg + "'");

        msg = "bbb.www";
        channel.basicPublish(Config.TOPIC_EXCHANGE_NAME, msg, null, msg.getBytes());
        System.out.println(" [x] Sent '" + msg + "'");

        msg = "www";
        channel.basicPublish(Config.TOPIC_EXCHANGE_NAME, msg, null, msg.getBytes());
        System.out.println(" [x] Sent '" + msg + "'");

    }
}
